﻿using System;
using System.Collections.Generic;
using CivilRegistry.ControlledModel.Extensions;

namespace CivilRegistry.ControlledModel
{
    /// <summary>
    /// The admin object.
    /// </summary>
    public partial class Admin : User
    {

        #region Local Fields

        /// <summary>
        /// The <see cref="BirthCertificate"/> <see cref="State"/> filter.
        /// </summary>
        private Func<BirthCertificate, bool> birthCertificateStateFilter = null;

        /// <summary>
        /// The <see cref="VoterCard"/> <see cref="State"/> filter.
        /// </summary>
        private Func<VoterCard, bool> voterCardStateFilter = null;

        /// <summary>
        /// The <see cref="RationCard"/> <see cref="State"/> filter.
        /// </summary>
        private Func<RationCard, bool> rationCardStateFilter = null;

        #endregion

        #region Constructors

        /// <summary>
        /// Constructs the <see cref="Admin"/> class.
        /// </summary>
        public Admin()
        {
            birthCertificateStateFilter = birthCertificate => birthCertificate.Person.PermanentAddress.District.State == this.PermanentAddress.District.State && birthCertificate.DenayReason == null;
            voterCardStateFilter = voterCard => voterCard.Person.PermanentAddress.District.State == this.PermanentAddress.District.State && voterCard.DenayReason == null;
            rationCardStateFilter = rationCard => rationCard.Family.Owner.PermanentAddress.District.State == this.PermanentAddress.District.State && rationCard.DenayReason == null;
        }

        #endregion

        #region Methods

        #region Finder Methods

        /// <summary>
        /// Finds the <see cref="Admin"/> by Id.
        /// </summary>
        /// <param name="id">The id of the <see cref="Admin"/>.</param>
        /// <returns>Found <see cref="Admin"/> object, null if not found.</returns>
        public static Admin FindById(int id)
        {
            return (Admin)repository.FindBy(user => user.UserId == id && user is Admin);
        }

        /// <summary>
        /// Retrives the deactive <see cref="Admin"/>s.
        /// </summary>
        /// <returns>The deactive <see cref="Admin"/>s.</returns>
        public static List<Admin> GetDeactiveRecords()
        {
            List<Admin> adminList = new List<Admin>();
            repository.FindAll(admin => admin.DeactivateReason != null).ForEach(admin => adminList.Add((Admin)admin));
            return adminList;
        }


        #endregion

        #region BirthCertificate Related Methods

        /// <summary>
        /// Retrives all <see cref="BirthCertificate"/>s.
        /// </summary>
        /// <returns>The <see cref="BirthCertificate"/>s.</returns>
        public List<BirthCertificate> GetAllBirthCertificates()
        {
            return BirthCertificate.FindAll(birthCertificateStateFilter);
        }

        /// <summary>
        /// Retrives the <see cref="BirthCertificate"/>s for approval.
        /// </summary>
        /// <returns>The <see cref="BirthCertificate"/>s for approval.</returns>
        public List<BirthCertificate> GetBirthCertificatesForApproval()
        {
            return BirthCertificate.GetNonApprovedRecords(birthCertificateStateFilter);
        }

        /// <summary>
        /// Retrives the <see cref="BirthCertificate"/>s for approval.
        /// </summary>
        /// <param name="includeDenayed">The denay flag.</param>
        /// <returns>The <see cref="BirthCertificate"/>s for approval.</returns>
        public List<BirthCertificate> GetBirthCertificatesForApproval(bool includeDenayed)
        {
            if(includeDenayed)
            {
                return BirthCertificate.GetNonApprovedRecords(birthCertificate => birthCertificate.Person.PermanentAddress.District.State == this.PermanentAddress.District.State);
            }

            return BirthCertificate.GetNonApprovedRecords(birthCertificateStateFilter);
        }

        /// <summary>
        /// Retrives the deactive <see cref="BirthCertificate"/>s.
        /// </summary>
        /// <returns>The deactive <see cref="BirthCertificate"/>s.</returns>
        public List<BirthCertificate> GetDeactiveBirthCertificates()
        {
            return BirthCertificate.GetDeactiveRecords(birthCertificateStateFilter);
        }

        /// <summary>
        /// Retrives the <see cref="BirthCertificate"/>s by provided condition.
        /// </summary>
        /// <param name="approved">The approved flag.</param>
        /// <param name="deactivated">The deactivated flag.</param>
        /// <returns>The filtered <see cref="BirthCertificate"/>s.</returns>
        public List<BirthCertificate> GetBirthCertificatesBy(bool approved, bool deactivated)
        {
            return BirthCertificate.GetRecordsBy(approved, deactivated, birthCertificateStateFilter);
        }

        /// <summary>
        /// To approve the <see cref="BirthCertificate"/>.
        /// </summary>
        /// <param name="birthCertificate">The <see cref="BirthCertificate"/> to approve.</param>
        /// <returns>The approved <see cref="BirthCertificate"/>.</returns>
        public BirthCertificate ApproveBirthCertificate(BirthCertificate birthCertificate)
        {
            birthCertificate.Required("birthCertificate");
            birthCertificate.IsApproved = true;
            birthCertificate.ApprovedUser = this;
            birthCertificate.ModifiedDate = DateTime.Now;
            birthCertificate.ModifiedUser = this;
            return BirthCertificate.Update(birthCertificate);
        }

        /// <summary>
        /// To deny the <see cref="BirthCertificate"/>.
        /// </summary>
        /// <param name="birthCertificate">The <see cref="BirthCertificate"/> to deny.</param>
        /// <param name="reason">The reason for deny.</param>
        /// <returns>The denyed <see cref="BirthCertificate"/>.</returns>
        public BirthCertificate DenayBirthCertificate(BirthCertificate birthCertificate, string reason)
        {
            birthCertificate.Required("birthCertificate");
            reason.Required("reason");
            birthCertificate.IsApproved = false;
            birthCertificate.DenayReason = reason;
            birthCertificate.ModifiedDate = DateTime.Now;
            birthCertificate.ModifiedUser = this;
            return BirthCertificate.Update(birthCertificate);
        }

        /// <summary>
        /// To deactivate the <see cref="BirthCertificate"/>.
        /// </summary>
        /// <param name="birthCertificate">The <see cref="BirthCertificate"/> to deactivate.</param>
        /// <param name="reason">The reason for deactivation.</param>
        /// <returns>The deactivated <see cref="BirthCertificate"/>.</returns>
        public BirthCertificate DeactivateBirthCertificate(BirthCertificate birthCertificate, string reason)
        {
            birthCertificate.Required("birthCertificate");
            reason.Required("reason");
            birthCertificate.DeactivateReason = reason;
            birthCertificate.ModifiedDate = DateTime.Now;
            birthCertificate.ModifiedUser = this;
            return BirthCertificate.Update(birthCertificate);
        }

        /// <summary>
        /// To reactivate the <see cref="BirthCertificate"/>.
        /// </summary>
        /// <param name="birthCertificate">The <see cref="BirthCertificate"/> to reactivate.</param>
        /// <returns>The reactivated <see cref="BirthCertificate"/>.</returns>
        public BirthCertificate ReActivateBirthCertificate(BirthCertificate birthCertificate)
        {
            birthCertificate.Required("birthCertificate");
            birthCertificate.DeactivateReason = null;
            birthCertificate.ModifiedDate = DateTime.Now;
            birthCertificate.ModifiedUser = this;
            return BirthCertificate.Update(birthCertificate);
        }

        /// <summary>
        /// To update the <see cref="BirthCertificate"/>.
        /// </summary>
        /// <param name="birthCertificate">The <see cref="BirthCertificate"/> to update.</param>
        /// <returns>The updated <see cref="BirthCertificate"/>.</returns>
        public BirthCertificate UpdateBirthCertificate(BirthCertificate birthCertificate)
        {
            birthCertificate.Required("birthCertificate");
            birthCertificate.ModifiedDate = DateTime.Now;
            birthCertificate.ModifiedUser = this;
            return birthCertificate.SaveChanges();
        }

        #endregion

        #region VoterCard Related Methods

        /// <summary>
        /// Retrives all <see cref="VoterCard"/>s.
        /// </summary>
        /// <returns>The <see cref="VoterCard"/>s.</returns>
        public List<VoterCard> GetAllVoterCards()
        {
            return VoterCard.FindAll(voterCardStateFilter);
        }

        /// <summary>
        /// Retrives the <see cref="VoterCard"/>s for approval.
        /// </summary>
        /// <returns>The <see cref="VoterCard"/>s for approval.</returns>
        public List<VoterCard> GetVoterCardsForApproval()
        {
            return VoterCard.GetNonApprovedRecords(voterCardStateFilter);
        }

        /// <summary>
        /// Retrives the <see cref="VoterCard"/>s for approval.
        /// </summary>
        /// <param name="includeDenayed">The denay flag.</param>
        /// <returns>The <see cref="VoterCard"/>s for approval.</returns>
        public List<VoterCard> GetVoterCardsForApproval(bool includeDenayed)
        {
            if (includeDenayed)
            {
                return VoterCard.GetNonApprovedRecords(voterCard => voterCard.Person.PermanentAddress.District.State == this.PermanentAddress.District.State);
            }

            return VoterCard.GetNonApprovedRecords(voterCardStateFilter);
        }

        /// <summary>
        /// Retrives the deactive <see cref="VoterCard"/>s.
        /// </summary>
        /// <returns>The deactive <see cref="VoterCard"/>s.</returns>
        public List<VoterCard> GetDeactiveVoterCards()
        {
            return VoterCard.GetDeactiveRecords(voterCardStateFilter);
        }

        /// <summary>
        /// Retrives the <see cref="VoterCard"/>s by provided condition.
        /// </summary>
        /// <param name="approved">The approved flag.</param>
        /// <param name="deactivated">The deactivated flag.</param>
        /// <returns>The filtered <see cref="VoterCard"/>s.</returns>
        public List<VoterCard> GetVoterCardsBy(bool approved, bool deactivated)
        {
            return VoterCard.GetRecordsBy(approved, deactivated, voterCardStateFilter);
        }

        /// <summary>
        /// To approve the <see cref="VoterCard"/>.
        /// </summary>
        /// <param name="voterCard">The <see cref="VoterCard"/> to approve.</param>
        /// <returns>The approved <see cref="VoterCard"/>.</returns>
        public VoterCard ApproveVoterCard(VoterCard voterCard)
        {
            voterCard.Required("voterCard");
            voterCard.VoterId = "UN0" + voterCard.VoterCardId;
            voterCard.IsApproved = true;
            voterCard.ApprovedUser = this;
            voterCard.ModifiedDate = DateTime.Now;
            voterCard.ModifiedUser = this;
            return VoterCard.Update(voterCard);
        }

        /// <summary>
        /// To deny the <see cref="VoterCard"/>.
        /// </summary>
        /// <param name="voterCard">The <see cref="VoterCard"/> to deny.</param>
        /// <param name="reason">The reason for deny.</param>
        /// <returns>The denyed <see cref="VoterCard"/>.</returns>
        public VoterCard DenayVoterCard(VoterCard voterCard, string reason)
        {
            voterCard.Required("voterCard");
            reason.Required("reason");
            voterCard.IsApproved = true;
            voterCard.DenayReason = reason;
            voterCard.ModifiedDate = DateTime.Now;
            voterCard.ModifiedUser = this;
            return VoterCard.Update(voterCard);
        }

        /// <summary>
        /// To deactivate the <see cref="VoterCard"/>.
        /// </summary>
        /// <param name="voterCard">The <see cref="VoterCard"/> to deactivate.</param>
        /// <param name="reason">The reason for deactivation.</param>
        /// <returns>The deactivated <see cref="VoterCard"/>.</returns>
        public VoterCard DeactivateVoterCard(VoterCard voterCard, string reason)
        {
            voterCard.Required("voterCard");
            reason.Required("reason");
            voterCard.DeactivateReason = reason;
            voterCard.ModifiedDate = DateTime.Now;
            voterCard.ModifiedUser = this;
            return VoterCard.Update(voterCard);
        }

        /// <summary>
        /// To reactivate the <see cref="VoterCard"/>.
        /// </summary>
        /// <param name="voterCard">The <see cref="VoterCard"/> to reactivate.</param>
        /// <returns>The reactivated <see cref="VoterCard"/>.</returns>
        public VoterCard ReActivateVoterCard(VoterCard voterCard)
        {
            voterCard.Required("voterCard");
            voterCard.DeactivateReason = null;
            voterCard.ModifiedDate = DateTime.Now;
            voterCard.ModifiedUser = this;
            return VoterCard.Update(voterCard);
        }

        /// <summary>
        /// To update the <see cref="VoterCard"/>.
        /// </summary>
        /// <param name="voterCard">The <see cref="VoterCard"/> to update.</param>
        /// <returns>The updated <see cref="VoterCard"/>.</returns>
        public VoterCard UpdateVoterCard(VoterCard voterCard)
        {
            voterCard.Required("voterCard");
            voterCard.ModifiedDate = DateTime.Now;
            voterCard.ModifiedUser = this;
            return voterCard.SaveChanges();
        }

        #endregion

        #region RationCard Related Methods

        /// <summary>
        /// Retrives all <see cref="RationCard"/>s.
        /// </summary>
        /// <returns>The <see cref="RationCard"/>s.</returns>
        public List<RationCard> GetAllRationCards()
        {
            return RationCard.FindAll(rationCardStateFilter);
        }

        /// <summary>
        /// Retrives the <see cref="RationCard"/>s for approval.
        /// </summary>
        /// <returns>The <see cref="RationCard"/>s for approval.</returns>
        public List<RationCard> GetRationCardsForApproval()
        {
            return RationCard.GetNonApprovedRecords(rationCardStateFilter);
        }

        /// <summary>
        /// Retrives the <see cref="RationCard"/>s for approval.
        /// </summary>
        /// <param name="includeDenayed">The denay flag.</param>
        /// <returns>The <see cref="RationCard"/>s for approval.</returns>
        public List<RationCard> GetRationCardsForApproval(bool includeDenayed)
        {
            if (includeDenayed)
            {
                return RationCard.GetNonApprovedRecords(rationCard => rationCard.Family.Owner.PermanentAddress.District.State == this.PermanentAddress.District.State);
            }

            return RationCard.GetNonApprovedRecords(rationCardStateFilter);
        }

        /// <summary>
        /// Retrives the deactive <see cref="RationCard"/>s.
        /// </summary>
        /// <returns>The deactive <see cref="RationCard"/>s.</returns>
        public List<RationCard> GetDeactiveRationCards()
        {
            return RationCard.GetDeactiveRecords(rationCardStateFilter);
        }

        /// <summary>
        /// Retrives the <see cref="RationCard"/>s by provided condition.
        /// </summary>
        /// <param name="approved">The approved flag.</param>
        /// <param name="deactivated">The deactivated flag.</param>
        /// <returns>The filtered <see cref="RationCard"/>s.</returns>
        public List<RationCard> GetRationCardsBy(bool approved, bool deactivated)
        {
            return RationCard.GetRecordsBy(approved, deactivated, rationCardStateFilter);
        }

        /// <summary>
        /// To approve the <see cref="RationCard"/>.
        /// </summary>
        /// <param name="rationCard">The <see cref="RationCard"/> to approve.</param>
        /// <returns>The approved <see cref="RationCard"/>.</returns>
        public RationCard ApproveRationCard(RationCard rationCard)
        {
            rationCard.Required("rationCard");
            rationCard.IsApproved = true;
            rationCard.ApprovedUser = this;
            rationCard.ModifiedDate = DateTime.Now;
            rationCard.ModifiedUser = this;
            return RationCard.Update(rationCard);
        }

        /// <summary>
        /// To approve add member to <see cref="RationCard"/> request.
        /// </summary>
        /// <param name="rationCard">The <see cref="RationCard"/> to add.</param>
        /// <param name="request">The <see cref="RationCardAlterRequest"/>.</param>
        /// <returns>The updated <see cref="RationCard"/>.</returns>
        public RationCard ApproveRationCardAddMember(RationCard rationCard, RationCardAlterRequest request)
        {
            rationCard.Required("rationCard");
            request.Required("request");

            rationCard.Family.Members.Add(request.ApplicableUser);
            rationCard.ModifiedDate = DateTime.Now;
            rationCard.ModifiedUser = this;

            RationCardAlterRequest.Delete(request);
            return RationCard.Update(rationCard);
        }

        /// <summary>
        /// To approve remove member from <see cref="RationCard"/> request.
        /// </summary>
        /// <param name="rationCard">The <see cref="RationCard"/> to remove.</param>
        /// <param name="request">The <see cref="RationCardAlterRequest"/>.</param>
        /// <returns>The updated <see cref="RationCard"/>.</returns>
        public RationCard ApproveRationCardRemoveMember(RationCard rationCard, RationCardAlterRequest request)
        {
            rationCard.Required("rationCard");
            request.Required("request");

            rationCard.Family.Members.Remove(request.ApplicableUser);
            rationCard.ModifiedDate = DateTime.Now;
            rationCard.ModifiedUser = this;

            RationCardAlterRequest.Delete(request);
            return RationCard.Update(rationCard);
        }

        /// <summary>
        /// To deny the <see cref="RationCard"/>.
        /// </summary>
        /// <param name="rationCard">The <see cref="RationCard"/> to deny.</param>
        /// <param name="reason">The reason for deny.</param>
        /// <returns>The denyed <see cref="RationCard"/>.</returns>
        public RationCard DenayRationCard(RationCard rationCard, string reason)
        {
            rationCard.Required("rationCard");
            reason.Required("reason");
            rationCard.IsApproved = true;
            rationCard.DenayReason = reason;
            rationCard.ModifiedDate = DateTime.Now;
            rationCard.ModifiedUser = this;
            return RationCard.Update(rationCard);
        }

        /// <summary>
        /// To deny <see cref="RationCard"/> add member request.
        /// </summary>
        /// <param name="request">The <see cref="RationCardAlterRequest"/>.</param>
        public void DenayRationCardAddMember(RationCardAlterRequest request)
        {
            request.Required("request");
            RationCardAlterRequest.Delete(request);
        }

        /// <summary>
        /// To deny <see cref="RationCard"/> remove member request.
        /// </summary>
        /// <param name="request">The <see cref="RationCardAlterRequest"/>.</param>
        public void DenayRationCardRemoveMember(RationCardAlterRequest request)
        {
            request.Required("request");
            RationCardAlterRequest.Delete(request);
        }

        /// <summary>
        /// To deactivate the <see cref="RationCard"/>.
        /// </summary>
        /// <param name="rationCard">The <see cref="RationCard"/> to deactivate.</param>
        /// <param name="reason">The reason for deactivation.</param>
        /// <returns>The deactivated <see cref="RationCard"/>.</returns>
        public RationCard DeactivateRationCard(RationCard rationCard, string reason)
        {
            rationCard.Required("rationCard");
            reason.Required("reason");
            rationCard.DeactivateReason = reason;
            rationCard.ModifiedDate = DateTime.Now;
            rationCard.ModifiedUser = this;
            return RationCard.Update(rationCard);
        }

        /// <summary>
        /// To reactivate the <see cref="RationCard"/>.
        /// </summary>
        /// <param name="rationCard">The <see cref="RationCard"/> to reactivate.</param>
        /// <returns>The reactivated <see cref="RationCard"/>.</returns>
        public RationCard ReActivateRationCard(RationCard rationCard)
        {
            rationCard.Required("rationCard");
            rationCard.DeactivateReason = null;
            rationCard.ModifiedDate = DateTime.Now;
            rationCard.ModifiedUser = this;
            return RationCard.Update(rationCard);
        }

        /// <summary>
        /// To update the <see cref="RationCard"/>.
        /// </summary>
        /// <param name="rationCard">The <see cref="RationCard"/> to update.</param>
        /// <returns>The updated <see cref="RationCard"/>.</returns>
        public RationCard UpdateRationCard(RationCard rationCard)
        {
            rationCard.Required("rationCard");
            rationCard.ModifiedDate = DateTime.Now;
            rationCard.ModifiedUser = this;
            return rationCard.SaveChanges();
        }

        #endregion

        #region Person Related Methods

        /// <summary>
        /// To create <see cref="Person"/> account.
        /// </summary>
        /// <param name="person">The <see cref="Person"/> to create.</param>
        /// <returns>Created <see cref="Person"/>.</returns>
        public Person CreatePersonAccount(Person person)
        {
            person.Required("person");
            return (Person)this.Insert(person);
        }

        /// <summary>
        /// To modify the <see cref="Person"/>.
        /// </summary>
        /// <param name="person">The <see cref="Person"/> to modify.</param>
        /// <returns>The modified <see cref="Person"/> object.</returns>
        public Person ModifyPersonAccount(Person person)
        {
            person.Required("person");
            return (Person)this.Update(person);
        }

        #endregion

        #endregion
    }
}